#include <QFile>
#include "riskmeasuretablemodel.h"
#include "riskmeasureeditor.h"
#include <iostream>

using namespace boost;
using namespace quic;
using namespace std;

RiskMeasureEditor::RiskMeasureEditor(Ui::MainWindow *ui, QObject *parent) :
    QObject(parent), riskMeasureConfig("risk_measures")
{        
    this->ui = ui;

    // read riskmeasure configuration xml
    QFile file("riskmeasures.xml");

    if( !file.open( QIODevice::ReadOnly ) )
      throw "Failed to open riskmeasures.xml";
    if( !riskMeasureConfig.setContent( &file ) )
    {
      file.close();
      throw "Failed to set content of XML document";
    }    

    file.close();

    // Index the risk measures
    for(QDomNode n = riskMeasureConfig.firstChild().firstChild(); !n.isNull(); n = n.nextSibling())
    {
        riskMeasureMap[n.firstChildElement("name").text()] = n;
        riskMeasureModuleMap[n.firstChildElement("module").text()] = n;
    }

    // setup signal and slots
    connect(ui->cmbName,SIGNAL(activated(QString)),this,SLOT(nameChanged(QString)));
    connect(ui->cmbName,SIGNAL(activated(QString)),this,SLOT(attributeChanged(QString)));
    connect(ui->ckbStored,SIGNAL(stateChanged(int)),this,SLOT(attributeChanged(int)));
    connect(ui->cmbInputName1,SIGNAL(activated(QString)),this,SLOT(inputName1Changed(QString)));
    connect(ui->cmbInputOutput1,SIGNAL(activated(QString)),this,SLOT(attributeChanged(QString)));
    connect(ui->cmbInputName2,SIGNAL(activated(QString)),this,SLOT(inputName2Changed(QString)));
    connect(ui->cmbInputOutput2,SIGNAL(activated(QString)),this,SLOT(attributeChanged(QString)));
    connect(ui->cmbInputName3,SIGNAL(activated(QString)),this,SLOT(inputName3Changed(QString)));
    connect(ui->cmbInputOutput3,SIGNAL(activated(QString)),this,SLOT(attributeChanged(QString)));
}

void RiskMeasureEditor::nameChanged(const QString &)
{
    QString module(riskMeasureMap[ui->cmbName->currentText()].firstChildElement("module").text());
    ui->lblModule->setText(module);    
}

void RiskMeasureEditor::inputNameChanged(int inputNum, const QString &inputName)
{
    QComboBox *cmbInputOutput;
    if(inputNum == 1)
        cmbInputOutput = ui->cmbInputOutput1;
    else if(inputNum == 2)
        cmbInputOutput = ui->cmbInputOutput2;
    else
        cmbInputOutput = ui->cmbInputOutput3;

    cmbInputOutput->clear();
    QStringList &list = inputList[inputName];
    cmbInputOutput->setEnabled(!list.isEmpty());
    cmbInputOutput->addItems(list);
}

/**
  * this gets triggered when a risk measure is selected
  */
void RiskMeasureEditor::riskMeasureSelected(const QModelIndex & index)
{   
    RiskMeasureTableModel *riskMeasureModel = dynamic_cast<RiskMeasureTableModel *>(ui->riskMeasureTable->model());
    riskMeasure = riskMeasureModel->getRiskMeasure(index.row());
    ui->ckbStored->setChecked(riskMeasure->isStored());
    ui->ckbStored->setEnabled(true);
    setupRiskMeasureName();
    setupInputs();
    ui->btnApply->setEnabled(false);
    ui->btnReset->setEnabled(false);
}

void RiskMeasureEditor::attributeChanged()
{
    ui->btnApply->setEnabled(true);
    ui->btnReset->setEnabled(true);
}

void RiskMeasureEditor::setupInputs()
{
    setupInput(*ui->cmbInputName1, *ui->cmbInputOutput1, 0);
    setupInput(*ui->cmbInputName2, *ui->cmbInputOutput2, 1);
    setupInput(*ui->cmbInputName3, *ui->cmbInputOutput3, 2);
}

void RiskMeasureEditor::setupInput(QComboBox &cmbInputName, QComboBox &cmbInputOutput, int parentIndex)
{
    // reset to combo boxes
    cmbInputName.clear();
    cmbInputOutput.clear();

    // if there are no parent with this index, then forget it and disable the inputs
    if(parentIndex >= riskMeasure->parents.size())
    {
        cmbInputName.setEnabled(false);
        cmbInputOutput.setEnabled(false);
        return;
    }
    else
    {
        // enable and clear the combo boxes
        cmbInputName.setEnabled(true);
        cmbInputOutput.setEnabled(true);
    }

    QString selectedName(riskMeasure->parents[parentIndex]->getName().c_str());
    // Populate the combo boxes
    for(QMap<QString,QStringList>::iterator it = inputList.begin();
        it != inputList.end(); it++)
    {
        cmbInputName.addItem(it.key());
        if(it.key() == selectedName)
        {
            cmbInputName.setCurrentIndex(cmbInputName.count()-1);
        }
    }

    inputNameChanged(parentIndex+1,selectedName);
}

void RiskMeasureEditor::setupRiskMeasureName()
{
    QComboBox &cmbName = *ui->cmbName;
    cmbName.setEnabled(true);
    cmbName.clear();
    QString selectedName(riskMeasure->getName().c_str());
    for(QMap<QString,QDomNode>::iterator it = riskMeasureMap.begin();
        it != riskMeasureMap.end(); it++)
    {
        cmbName.addItem(it.key());
        if(it.key() == selectedName)
            cmbName.setCurrentIndex(cmbName.count()-1);
    }

    ui->lblModule->setText(riskMeasure->getModule().c_str());
    setupParameters();
}

void RiskMeasureEditor::setupParameters()
{
    QLineEdit *txtParams[3];
    txtParams[0] = ui->txtParam1;
    txtParams[1] = ui->txtParam2;
    txtParams[2] = ui->txtParam3;

    for(unsigned int i=0; i<3; i++)
    {
        // TODO: enabling should be based on XML configuration
        if(i<riskMeasure->parameters.size())
        {
            txtParams[i]->setEnabled(true);
            txtParams[i]->setText(riskMeasure->parameters[i].c_str());
        }
        else
        {
            txtParams[i]->setEnabled(false);
            txtParams[i]->setText("");
        }
    }

}

void RiskMeasureEditor::setRiskMeasureRoot(shared_ptr<RiskMeasure> riskMeasureRoot)
{
    inputList.clear();
    indexRiskMeasure(riskMeasureRoot);
}

/**
 * Look through the list defined in risk measure graph
 * for each risk measure
 *   look for the module in the configration xml
 *     if found add the sublist to the map
 */
void RiskMeasureEditor::indexRiskMeasure(shared_ptr<RiskMeasure> riskMeasure)
{
    // If already seen this name, don't repeat (this happens as riskMeasure is a graph not a tree)
    if(inputList.find(riskMeasure->getName().c_str()) != inputList.end())
        return;

    // Find sublist of a risk measure
    QMap<QString,QDomNode>::iterator it = riskMeasureModuleMap.find(riskMeasure->getModule().c_str());

    // init sublist
    QStringList subList;

    // if found, populate the list
    if(it != riskMeasureModuleMap.end())
    {
        for(QDomNode n = it->firstChildElement("outputs").firstChild(); !n.isNull(); n = n.nextSibling())
            subList << n.firstChildElement("name").text();
    }

    // add to input list map
    inputList[riskMeasure->getName().c_str()] = subList;

    // Go through children recursively
    for(RiskMeasure::Children::iterator it = riskMeasure->children.begin();
        it != riskMeasure->children.end(); ++it)
    {
        indexRiskMeasure(*it);
    }
}
